package org.termine.jsf;

import java.io.Serializable;
import java.util.Date;
import java.util.List;

import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;

import org.termine.db.RedisConnector;
import org.termine.entity.Location;
import org.termine.entity.ProviderAvailability;
import org.termine.entity.ServiceSelectItem;
import org.termine.logic.AppointmentManager;
import org.termine.util.ConfigurationBean;

@ManagedBean
@ViewScoped
public class AppointmentSecondStageJSF extends BaseJSF implements Serializable {

	private static final long serialVersionUID = -4233256107429242217L;

	@ManagedProperty(value = "#{loginJSF}")
	private LoginJSF loginJSF;
	@ManagedProperty(value = "#{appointmentManager}")
	private AppointmentManager appointmentManager;
	@ManagedProperty(value = "#{redisConnector}")
	private RedisConnector redisConnector;
	@ManagedProperty(value="#{configurationBean}")
	private ConfigurationBean configurationBean;

	private ServiceSelectItem selectedService;
	private Location selectedLocation;
	private Date start;
	private List<ProviderAvailability> availabilities;

	/*
	 * Init
	 */
	@PostConstruct
	public void init() {
		if (!Boolean.parseBoolean(this.configurationBean.getProperty("use_redis"))) {
			this.selectedService = (ServiceSelectItem) FacesContext.getCurrentInstance()
					.getExternalContext().getSessionMap()
					.get(this.getLoginJSF().getSessionKey() + "_selectedservice");
			this.selectedLocation = (Location) FacesContext.getCurrentInstance().getExternalContext()
					.getSessionMap().get(this.getLoginJSF().getSessionKey() + "_selectedlocation");
		}

		this.start = new Date();
		this.selectedService = this.getSelectedService();
		this.selectedLocation = this.getSelectedLocation();
		this.availabilities = this.getAppointmentManager().getAllProviderAvailabilitiesForProvider(
				this.selectedService.getProviderId());
	}

	/*
	 * Jsf Action Methods
	 */
	public String addAppointment() {
		String result = this.getAppointmentManager().addAppointment(this.selectedLocation, this.selectedService,
				this.start, this.getLoginJSF().getPersonalData().getClient_id());
		if (result.equals("SUCCESS")) {
			this.init();
			this.setInfoMessage("The appointment has been saved successfully!");
			return "SUCCESS";
		} else if (result.equals("NOT_WITHIN_BOOKING_DEADLINE")) {
			this.setErrorMessage("The appointment could not be saved! The booking deadline for this service is "
					+ this.selectedService.getBookDeadlineInMin() + " minutes.");
			return "ERROR";
		} else if (result.equals("OVERLAP_WITH_APPOINTMENT")) {
			this.setErrorMessage("The appointment could not be saved! It overlaps with an existing appointment.");
			return "ERROR";
		} else if (result.equals("NO_AVAILABILITY")) {
			this.setErrorMessage("The appointment could not be saved! The service provider is not available at this time.");
			return "ERROR";
		} else if (result.equals("UNAVAILABLE")) {
			this.setErrorMessage("The appointment could not be saved! The service provider is unavailable at this time.");
			return "ERROR";
		} else if (result.equals("BEFORE_APPOINTMENT_TRAVEL_OVERLAP")) {
			this.setErrorMessage("The appointment could not be saved! The service provider cannot reach your location in time.");
			return "ERROR";
		} else if (result.equals("AFTER_APPOINTMENT_TRAVEL_OVERLAP")) {
			this.setErrorMessage("The appointment could not be saved! The service provider cannot reach the next appointment in time.");
			return "ERROR";
		} else {
			this.setFatalMessage("The (un)availability could not be saved! An error occurred.");
			return "ERROR";
		}
	}

	/*
	 * Session Variables
	 */
	public ServiceSelectItem getSelectedService() {
		if (Boolean.parseBoolean(this.configurationBean.getProperty("use_redis"))) {
			return (ServiceSelectItem) this.redisConnector.get(this.getLoginJSF().getSessionKey()
					+ "_selectedservice");
		} else {
			return this.selectedService;
		}
	}

	public void setSelectedService(ServiceSelectItem selectedService) {
		if (Boolean.parseBoolean(this.configurationBean.getProperty("use_redis"))) {
			this.redisConnector.setExp(this.getLoginJSF().getSessionKey() + "_selectedservice",
					RedisConnector.toString(selectedService));
		} else {
			this.selectedService = selectedService;
		}
	}

	public Location getSelectedLocation() {
		if (Boolean.parseBoolean(this.configurationBean.getProperty("use_redis"))) {
			return (Location) this.redisConnector.get(this.getLoginJSF().getSessionKey()
					+ "_selectedlocation");
		} else {
			return this.selectedLocation;
		}
	}

	public void setSelectedLocation(Location selectedLocation) {
		if (Boolean.parseBoolean(this.configurationBean.getProperty("use_redis"))) {
			this.redisConnector.setExp(this.getLoginJSF().getSessionKey() + "_selectedlocation",
					RedisConnector.toString(selectedLocation));
		} else {
			this.selectedLocation = selectedLocation;
		}
	}

	/*
	 * Getters & Setters
	 */
	public LoginJSF getLoginJSF() {
		return this.loginJSF;
	}

	public void setLoginJSF(LoginJSF loginJSF) {
		this.loginJSF = loginJSF;
	}

	public AppointmentManager getAppointmentManager() {
		return this.appointmentManager;
	}

	public void setAppointmentManager(AppointmentManager appointmentManager) {
		this.appointmentManager = appointmentManager;
	}

	public Date getStart() {
		return this.start;
	}

	public void setStart(Date start) {
		this.start = start;
	}

	public List<ProviderAvailability> getAvailabilities() {
		return this.availabilities;
	}

	public void setAvailabilities(List<ProviderAvailability> availabilities) {
		this.availabilities = availabilities;
	}

	public RedisConnector getRedisConnector() {
		return this.redisConnector;
	}

	public void setRedisConnector(RedisConnector redisConnector) {
		this.redisConnector = redisConnector;
	}

	public ConfigurationBean getConfigurationBean() {
		return this.configurationBean;
	}

	public void setConfigurationBean(ConfigurationBean configurationBean) {
		this.configurationBean = configurationBean;
	}

}
